/** @file
 * Implements a simple register based virtual machine with a 2d array of
 * processes competeing for energy and space for digital life simulation.
 */
#ifndef _CELLVM_H
#define _CELLVM_H

#include "config.h"
#include "cellvmcb.h"

/********** TWEAKABLE **************/
/** Size of cell instruction cache. */
#define CSIZE 32

/** Horizontal cell cluster resolution. */
#define X 200
/** Vertical cell cluster resolution. */
#define Y 200

/** Default cell energy. PROB TEMP. */
#define ENERGY 100
/** 1/X chance a weaker cell will win a cell_vs. */
#define LUCKYCHANCE 1000

/******* END TWEAKBLE*************/

/** Null instruction, does nothing. */
#define NOOP 0x00 
/** Stop instruction, stops the current program and returns the vm. */
#define STOP 0x01
/** Increment instruction, increments the proccess register by 1. */
#define INCR 0x02
/** Deincrement instruction, deincrements the proccess register by 1. */
#define DNCR 0x03
/** Zero instruction, sets the proccess register to 0. */
#define ZERO 0x04
/** Turn instruction, sets cell direction for CRCH and SPOR to the value in the proc reg. */
#define TURN 0x05
/** Crunch instruction, attempts to eat the energy of a process pointed to by direction. */
#define CRCH 0x06
/** Spor instruction, attempts to spore a copy proc in the space pointed to by direction. */
#define SPOR 0x07
/** TODO */
#define RDIR 0x08

/** Possible values for the direction register. */
enum DIRECTIONS {
	LEFT,
	RIGHT,
	UP,
	DOWN
};

/** Random number between 0 and X. */
#define RANDX (rand() % X)
/** Random number between 0 and Y. */
#define RANDY (rand() % Y)

/** Invovidual cell proccess. */
struct cell_proc {
	/** Generation level of the cell. */
	unsigned long gen;
	/** Cells energy level which deturmins how many instructions it can exec. */
	unsigned int energy;
	/** Instruction cache. Holds instructions to be executed by the VM. */
	char instructions[CSIZE];
};

/**TODO*/
struct cluster_stats {
	/**TODO*/
	unsigned long energy_death;
	/**TODO*/
	unsigned long spor_copies;
	/**TODO*/
	unsigned long vs_lucky;
};

/** Holds a cluster of computeable cells. */
struct cell_cluster {
	/** 2d 'table' array of cells. */
	struct cell_proc *cells[X][Y];
	/** VM ticks. Incremented each time a cell finishes executeing. */
	unsigned long tick;
	/**TODO*/
	struct cluster_stats stats;
	/** Callback subsystem structure, keeps track of callbacks registered to this VM. */
	struct callback_stack callbacks;
};

/**
 * Init a cell_cluster structure, must be done before use to allocate
 * space for the cell array. 
 * @param cluster Cluster to init.
 * @return 0 on ok, 1 on fail. 
 */
int cluster_init(struct cell_cluster *cluster);

/**
 * Free a cell_cluster structure init'd with cluster_init.
 * @param cluster Cluster structure to deallocate.
 */
void cluster_free(struct cell_cluster *cluster);

/**
 * Reap a cell if it has no energy left.
 * @param cluster Cluster to reap cell from.
 * @param x X coord of the cell.
 * @param y Y coord of the cell.
 * @return 0 on OK, something else on fail.
 */
int cell_reap(const struct cell_cluster *cluster, int x, int y);

/**
 * Scheduler, hands processes over to proc_cell for processing.
 * @param cluster Cluster containing cell processes to schedule.
 * @return 0
 */
int cluster_sched(struct cell_cluster *cluster);

/**
 * Core cell logic processor, process the cell at the given co-ords instructions.
 * @param cluster Cluster with the cell to compute.
 * @param x Horizontal co-ords of the cell.
 * @param y Vertical co-ords of the cell.
 * @param TODO
 * @return The cell proccessed on success, NULL on fail.
 */
struct cell_proc *proc_cell(const struct cell_cluster *cluster, int x, int y, char *didstuff);

/**
 *
 */
int get_neighbour_coords(int x, int y, int direction, int *xp, int *yp);

/**
 * Get the neighbour specified by direction reletive to the cell at the coords specified. 
 * @param cluster Cell cluster to get cell from.
 * @param x Horizontal co-ords.
 * @param y Vertical co-ords.
 * @param direction Direction of neighbour reletive to specified cell co-ords, LEFT,RIGHT,UP,DOWN. 
 */
struct cell_proc *get_neighbour(const struct cell_cluster *cluster, int x, int y, int direction);

/**
 * Populate the cell at the co-ords specified with the cell attributes also specified.
 * @param cluster Cluster containing the cell to modify.
 * @param x Horizontal co-ords.
 * @param y Vertical co-ords.
 * @param gen Cell generation.
 * @param energy Cell energy level.
 * @param instructions Cell instruction set.
 */
void cell_pop(const struct cell_cluster *cluster, int x, int y, int gen, int energy, const char instructions[CSIZE]);

#endif

